package cn.micro.system.manage.aspect;

import cn.micro.system.manage.annotate.PrivacyEncrypt;
import cn.micro.system.manage.annotate.PrivacyKeyAnnotation;
import cn.micro.system.manage.common.enums.PrivacyTypeEnum;
import cn.micro.system.manage.common.utils.DesensitizedUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;

@Component
@Aspect
@Slf4j
public class PrivacyKeyAspect {
    /**
     * @Description: 环绕通知包含此注解的
     * @param: ProceedingJoinPoint joinPoint
     * @return: Object
     */
    @Around(value = "@annotation(cn.micro.system.manage.annotate.PrivacyKeyAnnotation)")
    public Object repeatSub(ProceedingJoinPoint joinPoint) throws Throwable {
        return joinPoint.proceed();
    }

    /**
     * @Description: 后置通知
     */
    @AfterReturning(value = "@annotation(cn.micro.system.manage.annotate.PrivacyKeyAnnotation)",returning = "result")
    public void setPrivacyKeyType(JoinPoint joinPoint, Object result) throws Throwable {
        //进行注解 值获取
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //是否开启脱敏
        boolean flag = method.getDeclaredAnnotation(PrivacyKeyAnnotation.class).isKey();
        //是否对分页进行脱敏
        boolean status = method.getDeclaredAnnotation(PrivacyKeyAnnotation.class).isPageKey();
        if (!status) {
            //进行返回值反射
            //进行单值返回
            Class<?> aClass = result.getClass();
            if (null != aClass){
                //对象属性修改
                setFieldMethod(result, flag, aClass);
            }
        } else {
            //反射分页page
            //反射list类型
            Parameter[] parameters = signature.getMethod().getParameters();
            //泛型名称
            String name = parameters[0].getName();
            //泛型class
            Class<?> type = parameters[0].getType();
            //包名
            String typeName = type.getName();
            PropertyDescriptor[] ps = Introspector.getBeanInfo(result.getClass(), Object.class).getPropertyDescriptors();
            for (PropertyDescriptor prop : ps) {
                //prop.getPropertyType() == List.class
                if (prop.getPropertyType().isAssignableFrom(List.class)) { //List 集合类型
                    Object obj = result.getClass().getMethod(prop.getReadMethod().getName()).invoke(result);
                    if(obj !=null){
                        List<?> listObj = (List<?>) obj;
                        for (Object next : listObj) {
                            Class<?> classObj = Class.forName(typeName);
                            //进属性修改
                            setFieldMethod(next,flag,classObj);
                        }
                    }

                }
            }
        }
    }

    /**
     * 内容填充
     */
    private void setFieldMethod(Object result, boolean flag, Class<?> aClass) throws IllegalAccessException {
        List<Field> fieldList = getFieldList(aClass);
        //循环遍历
        for (Field field : fieldList) {
            field.setAccessible(true); // 设置属性可访问
            // 获取指定类型的注解
            PrivacyEncrypt myAnnotation = field.getDeclaredAnnotation(PrivacyEncrypt.class);
            if (myAnnotation != null) {
                //进行数据处理
                int intSuf = myAnnotation.suffixNoMaskLen();
                int intPre = myAnnotation.prefixNoMaskLen();
                String maskStr = myAnnotation.maskStr();
                PrivacyTypeEnum type = myAnnotation.type();
                Object obj = field.get(result);
                //返回脱敏的值
                Object str = setPrivacyInfo(type,obj,intSuf,intPre,maskStr);
                field.set(result,str);
            }
        }
    }
    //判断脱敏内容 返回脱敏值
    private Object setPrivacyInfo(PrivacyTypeEnum type, Object obj, int intSuf, int intPre, String maskStr) {
        Object newObj = null;
        if (obj !=null && null != type) {
            switch (type) {
                case CHINESE_NAME:
                    newObj = DesensitizedUtils.chineseName((String) obj);
                    break;
                case ID_CARD:
                    newObj = DesensitizedUtils.idCardNum((String) obj);
                    break;
                case FIXED_PHONE:
                    newObj = DesensitizedUtils.fixedPhone((String) obj);
                    break;
                case MOBILE_PHONE:
                    newObj = DesensitizedUtils.mobilePhone((String) obj);
                    break;
                case ADDRESS:
                    newObj = DesensitizedUtils.address((String) obj);
                    break;
                case EMAIL:
                    newObj = DesensitizedUtils.email((String) obj);
                    break;
                case BANK_CARD:
                    newObj = DesensitizedUtils.bankCard((String) obj);
                    break;
                case PASSWORD:
                    newObj = DesensitizedUtils.password((String) obj);
                    break;
                case KEY:
                    newObj = DesensitizedUtils.key((String) obj);
                    break;
                case CUSTOMER://自定义脱敏
                    newObj = DesensitizedUtils.desValue((String) obj, intPre, intSuf, maskStr);
                    break;
                default:
                    throw new IllegalArgumentException("Unknow sensitive type enum " + type);
            }
            return newObj;
        }else {
            return obj;
        }

    }
    //递归查询对象字段属性
    private List<Field> getFieldList(Class<?> clazz){
        if(null == clazz){
            return null;
        }
        List<Field> fieldList = new ArrayList<>();
        //递归查找
        while (clazz!=null){
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                if (field != null){
                    //设置属性的可访问性
                    field.setAccessible(true);
                    //过滤静态
                    if(Modifier.isStatic(field.getModifiers())){
                        continue;
                    }
                    //添加字段
                    fieldList.add(field);
                }
            }
            clazz = clazz.getSuperclass();
        }
        return fieldList;
    }

}
